import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.sound.sampled.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

// 音效处理类：负责加载、播放和管理音频资源
class SoundEffect {
    // 音频剪辑对象，用于存储和播放音频
    private Clip clip;
    
    // 构造方法：接收音效文件路径并初始化音频资源
    public SoundEffect(String soundFilePath) {
        try {
            // 创建音效文件对象
            File soundFile = new File(soundFilePath);
            // 打印文件存在性检查结果
            System.out.println("检查文件是否存在: " + soundFile.exists());
            // 打印文件绝对路径用于调试
            System.out.println("文件路径是否有效: " + soundFile.getAbsolutePath());
            
            // 若文件不存在则输出错误信息并返回
            if (!soundFile.exists()) {
                System.err.println("错误: 音效文件不存在 - " + soundFilePath);
                return;
            }
            // 打印文件可读状态
            System.out.println("文件可读: " + soundFile.canRead());
            
            // 从文件创建音频输入流
            AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(soundFile);
            // 获取音频剪辑对象
            clip = AudioSystem.getClip();
            
            // 获取音频格式信息
            AudioFormat format = audioInputStream.getFormat();
            // 打印音频格式信息
            System.out.println("音频格式: " + format);
            
            // 打开音频流并加载到剪辑
            clip.open(audioInputStream);
            // 打印加载成功提示
            System.out.println("音效加载成功");
        } catch (UnsupportedAudioFileException e) {
            // 捕获不支持的音频格式异常
            System.err.println("错误: 不支持的音频格式 - " + e.getMessage());
            e.printStackTrace();
        } catch (LineUnavailableException e) {
            // 捕获音频设备不可用异常
            System.err.println("错误: 音频行不可用 - " + e.getMessage());
            e.printStackTrace();
        } catch (IOException e) {
            // 捕获文件读取异常
            System.err.println("错误: 读取文件时IO异常 - " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            // 捕获其他未知异常
            System.err.println("错误: 加载音效时发生未知异常 - " + e.getMessage());
            e.printStackTrace();
        }
    }

    // 播放音效的方法：先停止当前播放再重新开始
    public void play() {
        if (clip != null) {
            // 若当前音效正在播放则停止
            if (clip.isRunning()) {
                clip.stop();
            }
            // 将播放位置重置为开始
            clip.setFramePosition(0);
            // 开始播放音效
            clip.start();
        }
    }

    // 关闭音效资源的方法：释放音频资源
    public void close() {
        if (clip != null && clip.isOpen()) {
            clip.close();
        }
    }
}

// 计算器主类：继承JFrame实现图形界面，实现ActionListener处理按钮点击事件
public class Calculator extends JFrame implements ActionListener {
    // 按钮点击音效对象
    private SoundEffect buttonClickSound;
    // 界面布局面板：北部面板和中心面板
    private JPanel north, center;
    // 显示计算结果的文本框
    private JTextField field;
    // 计算器按钮数组
    private JButton[] btns;
    
    // 音效开关状态变量：控制音效是否启用
    private boolean soundEnabled = true;
    // 定义操作符数组
    private final String[] operators = {"+", "-", "*", "/"};

    // 构造方法：初始化计算器界面
    public Calculator() {
        // 设置窗口标题
        setTitle("紫色主题计算器");
        // 设置窗口大小
        setSize(700, 700);
        // 设置关闭窗口时退出程序
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        // 设置窗口居中显示
        setLocationRelativeTo(null);
        // 初始化界面组件
        initComponent();
        // 设置窗口可见
        setVisible(true);
    }

    // 初始化界面组件的方法
    private void initComponent() {
        // 音效文件路径
        String soundPath = "D:\\Users\\28056\\Desktop\\music\\button_click.wav";
        // 打印加载音效文件的提示
        System.out.println("尝试加载音效文件: " + soundPath);
        // 初始化音效对象
        buttonClickSound = new SoundEffect(soundPath);
        // 若音效初始化失败则输出错误信息
        if (buttonClickSound == null) {
            System.err.println("音效初始化失败");
        }

        // 创建北部面板和中心面板
        north = new JPanel();
        center = new JPanel();
        // 创建显示文本框
        field = new JTextField();
        // 设置文本框首选尺寸
        field.setPreferredSize(new Dimension(700, 150));
        // 设置文本框不可编辑
        field.setEditable(false);
        // 设置文本框字体
        field.setFont(new Font("SansSerif", Font.BOLD, 35));
        
        // 设置窗口背景颜色为紫色
        getContentPane().setBackground(new Color(128, 0, 128));
        // 设置北部面板背景颜色为暗紫色
        north.setBackground(new Color(138, 43, 226));
        // 设置中心面板背景颜色为亮紫色
        center.setBackground(new Color(153, 51, 255));

        // 定义计算器按钮文本数组（数字、运算符和功能键）
        String[] str = new String[]{
                "7", "8", "9", "+",
                "4", "5", "6", "-",
                "1", "2", "3", "*",
                "0", ".", "=", "/",
                "C", "B", "T", "S"
        };
        // 初始化按钮数组
        btns = new JButton[str.length];
        // 设置按钮背景颜色为浅紫色
        Color buttonPurple = new Color(171, 130, 255);
        // 循环创建按钮并设置样式
        for (int i = 0; i < btns.length; i++) {
            btns[i] = new JButton(str[i]);
            btns[i].setFont(new Font("SansSerif", Font.BOLD, 25));
            btns[i].setBackground(buttonPurple);
            // 设置按钮文字颜色为白色
            btns[i].setForeground(Color.WHITE);
        }

        // 设置北部面板布局为边界布局
        north.setLayout(new BorderLayout());
        // 设置中心面板布局为5行4列网格布局
        center.setLayout(new GridLayout(5, 4));
        // 将文本框添加到北部面板中心位置
        north.add(field, BorderLayout.CENTER);

        // 将按钮添加到中心面板
        for (JButton btn : btns) {
            center.add(btn);
        }

        // 将北部面板添加到窗口北部，中心面板添加到窗口中心
        add(north, BorderLayout.NORTH);
        add(center);

        // 为所有按钮添加点击事件监听器
        for (JButton btn : btns) {
            btn.addActionListener(this);
        }
        
        // 修改S按钮初始文本，显示当前音效状态（开启）
        for (JButton btn : btns) {
            if ("S".equals(btn.getText())) {
                btn.setText("S(开)");
                break;
            }
        }
    }

    // 处理按钮点击事件的核心方法
    private void setBtnText(String text) {
        // 根据音效开关状态决定是否播放音效
        if (soundEnabled && buttonClickSound != null) {
            buttonClickSound.play();
        }

        // 特殊处理：输入框为空时按小数点自动补0（如".", "0."）
        if (".".equals(text) && field.getText().isEmpty()) {
            field.setText("0.");  // 设置文本为"0."
            return;              // 终止当前方法，避免后续处理
        }

        // 防止小数点连续出现
        if (".".equals(text) && field.getText().contains(".")) {
            field.setText(field.getText() + ""); // 不做任何操作，忽略重复小数点
            return;
        }

        // 防止操作符出现在开头
        if (isOperator(text) && (field.getText().isEmpty() || isOperator(field.getText().substring(0, 1)))) {
            field.setText(field.getText() + ""); // 不做任何操作，忽略开头操作符
            return;
        }

        // 根据按钮文本执行不同功能
        switch (text) {
            case "C": // 清空输入框
                field.setText("");
                break;
            case "B": // 回退删除最后一个字符
                String numText = field.getText();
                if (numText.length() != 0) {
                    String lastText = numText.substring(0, numText.length() - 1);
                    field.setText(lastText);
                }
                break;
            case "T": // 显示当前时间
                showCurrentTime();
                break;
            case "S": // 切换音效开关状态
                toggleSound();
                break;
            case "=": // 执行数学表达式计算
                calculate();
                break;
            default: // 普通数字或运算符输入
                String oldText = field.getText();
                field.setText(oldText + text);
                break;
        }
    }
    
    // 显示当前时间的方法
    private void showCurrentTime() {
        // 获取当前日期时间
        LocalDateTime now = LocalDateTime.now();
        // 创建日期时间格式化器（格式：年-月-日 时:分:秒）
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 格式化日期时间并显示在文本框
        String formattedDateTime = now.format(formatter);
        field.setText(formattedDateTime);
    }

    // 切换音效开关状态的方法
    private void toggleSound() {
        // 切换音效启用状态（true-开启，false-关闭）
        soundEnabled = !soundEnabled;
        // 在文本框显示当前音效状态
        field.setText(soundEnabled ? "音效已开启" : "音效已关闭");
        
        // 更新S按钮文本，显示当前音效状态
        for (JButton btn : btns) {
            // 匹配按钮文本为"S"或带状态标识的情况
            if ("S".equals(btn.getText()) || "S(开)".equals(btn.getText()) || "S(关)".equals(btn.getText())) {
                btn.setText(soundEnabled ? "S(开)" : "S(关)");
                break;
            }
        }
    }

    // 判断是否为操作符
    private boolean isOperator(String text) {
        for (String op : operators) {
            if (op.equals(text)) {
                return true;
            }
        }
        return false;
    }

    // 执行数学计算的方法
    private void calculate() {
        // 获取文本框中的计算表达式
        String expression = field.getText();
        // 创建脚本引擎管理器
        ScriptEngineManager manager = new ScriptEngineManager();
        // 获取JavaScript引擎（用于执行数学表达式计算）
        ScriptEngine engine = manager.getEngineByName("javascript");
        try {
            // 计算表达式并获取结果
            Object result = engine.eval(expression);
            // 将计算结果显示在文本框
            field.setText(result.toString());
        } catch (ScriptException e) {
            // 捕获计算异常并显示错误信息
            field.setText("运算错误");
            e.printStackTrace();
        }
    }

    // 实现ActionListener接口的点击事件处理方法
    @Override
    public void actionPerformed(ActionEvent a) {
        // 获取触发事件的对象
        Object source = a.getSource();
        // 若事件源是按钮组件
        if (source instanceof JButton) {
            JButton btn = (JButton) source;
            String text = btn.getText();
            // 处理带状态标识的按钮文本（如"S(开)"转换为"S"）
            if (text.startsWith("S(")) {
                text = "S";  // 提取功能标识
            }
            setBtnText(text);  // 调用按钮文本处理方法
        }
    }

    // 窗口销毁时的资源释放方法
    @Override
    public void dispose() {
        // 关闭音效资源，释放音频设备
        if (buttonClickSound != null) {
            buttonClickSound.close();
        }
        // 调用父类销毁方法，释放UI资源
        super.dispose();
    }

    // 主方法：程序入口点
    public static void main(String[] args) {
        // 在EDT线程中创建计算器实例（确保UI操作线程安全）
        SwingUtilities.invokeLater(Calculator::new);
    }
}